#include "thread.h"
#include "ARMCM3.h"

#define NVIC_INT_CTRL            0xE000Ed04    //寄存器地址
#define NVIC_PENDSVSET          0x10000000
#define NVIC_SYSPRI2              0xE000ED22    //寄存器地址
#define NVIC_PENDSV_PRI          0x000000FF

#define MEM32(addr)                *(volatile unsigned long *)(addr)
#define MEM8(addr)                 *(volatile unsigned char *)(addr)


void los_task_run(void) {
    //设置pendsv异常
    __set_PSP(0);
    MEM8(NVIC_SYSPRI2) = NVIC_PENDSV_PRI;
    MEM32(NVIC_INT_CTRL) = NVIC_PENDSVSET;
}

void los_task_switch() {
    MEM32(NVIC_INT_CTRL) = NVIC_PENDSVSET;  //触发异常
}

__asm void PendSV_Handler(void){
    
    IMPORT currentTask
    IMPORT nextTask
    //判断PSP寄存器是否为0
    MRS R0,PSP
    //不需要保存状态直接恢复
    CBZ R0,PendSVHandler_nosave
    //保存另外一些寄存器
    //此时R0指向哪里？
    STMDB R0!,{R4-R11}
    //把currentTask的地址 - > R1
    LDR R1,=currentTask
    //R1地址的内容 ->R1
    LDR R1,[R1]
    //让R1的内容保存栈顶的内容
    //即R1保存的是currentTask栈顶内容(压栈后的地址).
    STR R0,[R1]

PendSVHandler_nosave
    //交换
    LDR R0,=currentTask
    LDR R1,=nextTask
    LDR R2,[R1]
    STR R2,[R0]

    //取出堆栈地址
    LDR R0,[R2]
    LDMIA R0!,{R4-R11}

    //切换
    MSR PSP,R0
    // 为了在回到任务后，确保继续使用PSP堆栈
    ORR LR,LR,#0x04
    BX LR   //退出堆栈
}